﻿using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Xml.Linq;
using ICSharpCode.SharpZipLib.Zip;
using System.Net;
using System.Threading;
using System.Text.RegularExpressions;
using OpenNETCF.ToolHelp;
using XFControls.Utils;
using System.Diagnostics;

namespace XDAFacebook
{
    public partial class SplashScreen : Form
    {
        public bool CheckAuth;
        private string curVer = Settings.CurrentVersion;
        private string splashPictureLocation = "\\Resources\\splash.png";
        //private string versionURL = "http://forum.xda-developers.com/showpost.php?p=6404470";
        private string versionURL = "http://xda-winmo-facebook.googlecode.com/svn/wiki/CurrentVersion.wiki";
        private string _url;
        private string _updateDirectory = "\\updates";
        private string _filePath;
        private int percDone;
        private bool _import;

        public SplashScreen()
        {
            InitializeComponent();
            Settings.settingsFileName = XFControlUtils.GetCurrent_Directory() + Settings.settingsFileName;
            Settings.localizationDir = XFControlUtils.GetCurrent_Directory() + Settings.localizationDir;
            Settings.SkinDir = XFControlUtils.GetCurrent_Directory() + Settings.SkinDir;
            CheckAuth = false;

            deflateSkins();

            string splashImgLoc = XFControlUtils.GetCurrent_Directory() + splashPictureLocation;
            _import = Settings.ImportSettings();

            if (Settings.FirstRun != Settings.CurrentVersion) Settings.Skin = "hungelt8";

            if (File.Exists(Settings.SkinDir + "\\" + Settings.Skin + "\\splash.png"))
                splashImgLoc = Settings.SkinDir + "\\" + Settings.Skin + "\\splash.png";

            var backBit = new Bitmap(splashImgLoc);

            BackColor = backBit.GetPixel(0, 0);
            lblPercDone.BackColor = backBit.GetPixel(0, 0);

            SplashPicture.Image = backBit;
            SplashPicture.SizeMode = PictureBoxSizeMode.StretchImage;
            _updateDirectory = XFControlUtils.GetCurrent_Directory() + _updateDirectory;
        }

        private void SplashTimer_Tick(object sender, EventArgs e)
        {
            CleanInstances();
            SplashTimer.Enabled = false;
            if (_import)
            {
                importCache();

                var auth = new Authentication(Settings.auth_key);

                if (auth.TestForSuccess() != AuthenticationReturn.Success)
                {
                    removeAuthKey();
                }
            }

            CheckAuth = true;
            checkCurrentVersion();
        }

        private void CleanInstances()
        {
            FindAndKillProcess("XDAFacebook.exe");
        }

        //Namespaces needed

        public bool FindAndKillProcess(string name)
        {
            //here we're going to get a list of all running processes on
            //the computer
            ProcessEntry first = null;
            foreach (ProcessEntry clsProcess in ProcessEntry.GetProcesses())
            {
                //now we're going to see if any of the running processes
                //match the currently running processes by using the StartsWith Method,
                //this prevents us from incluing the .EXE for the process we're looking for.
                //. Be sure to not
                //add the .exe to the name you provide, i.e: NOTEPAD,
                //not NOTEPAD.EXE or false is always returned even if
                //notepad is running
                if (!clsProcess.ExeFile.StartsWith(name)) continue;

                if (first != null)
                    Restart(first, clsProcess, name);
                else
                    first = clsProcess;
            }
            //process not found, return false
            return false;
        }

        private static void Restart(ProcessEntry first, ProcessEntry clsProcess, string name)
        {
            MessageBox.Show(Settings.LocalizationStrings.AnotherInstance);
            Process.Start(XFControlUtils.GetCurrent_Directory() + "\\" + name, null);
            clsProcess.Kill();
            first.Kill();
        }

        private void importCache()
        {
            string skinPath = XFControlUtils.GetCurrent_Directory() + @"\Resources\";
            if (Settings.Skin != Settings.LocalizationStrings.Default && Directory.Exists(Settings.SkinDir + "\\" + Settings.Skin))
                skinPath = Settings.SkinDir + "\\" + Settings.Skin;

            WaitCallback cb = v => XFGraphics.DoImport(skinPath);

            ThreadPool.QueueUserWorkItem(cb);
        }

        private void checkCurrentVersion()
        {
            //Regex reg = new Regex(@"<div class='post-message' id=""post_message_6404470""><p>current version (?<version>.*?)<br />.*?\s<a.*?href=""(?<link>.*?)""", RegexOptions.IgnoreCase | RegexOptions.Multiline);
            Regex reg = new Regex(@"Current Version: (?<version>.*?)\s*?(?<link>http.*?.CAB)", RegexOptions.IgnoreCase | RegexOptions.Multiline);
            var html = WebDownloader.DownloadHTML(versionURL);
            if (reg.IsMatch(html))
            {
                var match = reg.Match(html);
                if (!match.Groups["version"].Value.Trim().Equals(curVer))
                {
                    if (MessageBox.Show(Settings.LocalizationStrings.AppOutOfDate, Settings.LocalizationStrings.outOfDate, MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                    {
                        _url = match.Groups["link"].Value;
                        _filePath = _updateDirectory + "\\update " + match.Groups["version"].Value + ".cab";

                        WaitCallback cb = StartDownload;
                        ThreadPool.QueueUserWorkItem(cb);

                        lblPercDone.Height = Screen.PrimaryScreen.WorkingArea.Height / 4;

                        while (percDone != 100)
                        {
                            lblPercDone.Text = Settings.LocalizationStrings.downloading + "\n" + percDone + "%";
                            Application.DoEvents();
                            Thread.Sleep(100);
                        }

                        lblPercDone.Text = Settings.LocalizationStrings.downloading + "\n" + percDone + "%";
                        Application.DoEvents();
                        MessageBox.Show(Settings.LocalizationStrings.downloadDone);

                        if (MessageBox.Show(Settings.LocalizationStrings.installNow, Settings.LocalizationStrings.Install, MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                        {
                            System.Diagnostics.Process.Start(_filePath, "");
                            Application.Exit();
                        }
                    }
                }
            }
        }

        private void deflateSkins()
        {
            foreach (var file in Directory.GetFiles(Settings.SkinDir))
            {
                var ext = Path.GetExtension(file);
                if (ext != ".zip") continue;

                UnZipFiles(file, Settings.SkinDir, "", true);
            }
        }

        private void StartDownload(object val)
        {
            try
            {
                if (!Directory.Exists(_updateDirectory))
                    Directory.CreateDirectory(_updateDirectory);

                var webReq = (HttpWebRequest)WebRequest.Create(_url);
                webReq.Headers.Add("Accept-Encoding", "gzip, deflate");

                using (var webRes = (HttpWebResponse)webReq.GetResponse())
                using (var fileBytes = AsyncWebDownloader.DeflateStream(webRes))
                using (var saveStream = new FileStream(_filePath, FileMode.Create, FileAccess.Write))
                {
                    var buffer = new byte[4096];
                    long bytesRead = 0;
                    long contentLength = webRes.ContentLength;

                    int read;

                    do
                    {
                        read = fileBytes.Read(buffer, 0, buffer.Length);
                        saveStream.Write(buffer, 0, read);
                        bytesRead += read;

                        percDone = (int)((bytesRead / (double)contentLength) * 100);
                    } while (read > 0);
                }
            }
            catch
            {
            }
            percDone = 100;
        }

        private void removeAuthKey()
        {
            var settings = XDocument.Load(Settings.settingsFileName);

            settings.Root.Element("auth_key").SetValue("");
            settings.Save(Settings.settingsFileName);
        }

        private void UnZipFiles(string zipPathAndFile, string outputFolder, string password, bool deleteZipFile)
        {
            var s = new ZipInputStream(File.OpenRead(zipPathAndFile));
            if (!string.IsNullOrEmpty(password))
                s.Password = password;
            ZipEntry theEntry;

            while ((theEntry = s.GetNextEntry()) != null)
            {
                string directoryName = outputFolder;
                string fileName = Path.GetFileName(theEntry.Name);
                // create directory 
                if (directoryName != "")
                {
                    Directory.CreateDirectory(directoryName);
                }

                if (fileName == String.Empty) continue;

                if (theEntry.Name.IndexOf(".ini") >= 0) continue;

                string fullPath = directoryName + "\\" + theEntry.Name;
                fullPath = fullPath.Replace("\\ ", "\\");

                if (File.Exists(fullPath)) continue;

                string fullDirPath = Path.GetDirectoryName(fullPath);
                
                if (!Directory.Exists(fullDirPath)) Directory.CreateDirectory(fullDirPath);

                FileStream streamWriter = File.Create(fullPath);
                var data = new byte[2048];
                while (true)
                {
                    int size = s.Read(data, 0, data.Length);
                    if (size > 0)
                    {
                        streamWriter.Write(data, 0, size);
                    }
                    else
                    {
                        break;
                    }
                }
                streamWriter.Close();
            }
            s.Close();
            if (deleteZipFile)
                File.Delete(zipPathAndFile);
        }
    }
}